#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include <iostream>
#include <sstream>

using namespace std;
using namespace cv;

static void help()
{
    cout
        << "\n--------------------------------------------------------------------------" << endl
        << "This program shows how to scan image objects in OpenCV (cv::Mat). As use case"
        << " we take an input image and divide the native color palette (255) with the "  << endl
        << "input. Shows C operator[] method, iterators and at function for on-the-fly item address calculation."<< endl
        << "Usage:"                                                                       << endl
        << "./howToScanImages imageNameToUse divideWith [G]"                              << endl
        << "if you add a G parameter the image is processed in gray scale"                << endl
        << "--------------------------------------------------------------------------"   << endl
        << endl;
}

Mat& ScanImageAndReduceC(Mat& I, const uchar* table);
Mat& ScanImageAndReduceIterator(Mat& I, const uchar* table);
Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar * table);

int main1( int argc, char* argv[])
{
	 VideoCapture cap(0);
	 Mat captured;
	 cap>>captured;
	 imshow("captured",captured);

	Mat I = imread("C:/Users/domenico/Pictures/success_1.jpg", CV_LOAD_IMAGE_COLOR);
	cout<<"R:"<<I.rows<<endl<<"cols:"<<I.cols<<endl<<"canali:"<<I.channels()<<endl;
	imshow("Input image",I);
	

	Mat edges;
        cvtColor(I, edges, CV_BGR2GRAY);

        Canny(edges, edges, 30, 60);

        imshow("window label", edges);


  Mat element = getStructuringElement( MORPH_RECT,
                       Size( 2*3 + 1, 2*3+1 ),
                       Point( 15, 15 ) );
  /// Apply the erosion operation

  Mat erosion_dst;
  dilate( I, erosion_dst, element );
  imshow( "Erosion Demo", erosion_dst );

  Mat new_image = Mat::zeros( I.size(), I.type() );
   for( int y = 0; y < I.rows; y++ )
       { for( int x = 0; x < I.cols; x++ )
            { for( int c = 0; c < 3; c++ )
                 {
         new_image.at<Vec3b>(y,x)[c] = 
            saturate_cast<uchar>( 0.5*( I.at<Vec3b>(y,x)[c] ) + 0.5 );
		  
		 waitKey();
                }
       }
       }

   imshow("res",new_image);

  while(true)
  {
	  cap>>captured;
	  
	  
	  imshow("Webcam",captured);
	 
	 
	 
	  
	//Vec3b t=captured.at<Vec3b>(1,1,1);
	 //cout<<"ccccc"<<endl;

	  waitKey(5);	//pausa di 5 millisec
	   
	    
  }

	waitKey();

	return 1;
    //help();
    //if (argc < 3)
    //{
    //    cout << "Not enough parameters" << endl;
    //    return -1;
    //}

    //Mat I, J;
    //if( argc == 4 && !strcmp(argv[3],"G") )
    //    I = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
    //else
    //    I = imread(argv[1], CV_LOAD_IMAGE_COLOR);

    //if (!I.data)
    //{
    //    cout << "The image" << argv[1] << " could not be loaded." << endl;
    //    return -1;
    //}

    //int divideWith = 0; // convert our input string to number - C++ style
    //stringstream s;
    //s << argv[2];
    //s >> divideWith;
    //if (!s || !divideWith)
    //{
    //    cout << "Invalid number entered for dividing. " << endl;
    //    return -1;
    //}

    //uchar table[256];
    //for (int i = 0; i < 256; ++i)
    //   table[i] = (uchar)(divideWith * (i/divideWith));

    //const int times = 100;
    //double t;

    //t = (double)getTickCount();

    //for (int i = 0; i < times; ++i)
    //{
    //    cv::Mat clone_i = I.clone();
    //    J = ScanImageAndReduceC(clone_i, table);
    //}

    //t = 1000*((double)getTickCount() - t)/getTickFrequency();
    //t /= times;

    //cout << "Time of reducing with the C operator [] (averaged for "
    //     << times << " runs): " << t << " milliseconds."<< endl;

    //t = (double)getTickCount();

    //for (int i = 0; i < times; ++i)
    //{
    //    cv::Mat clone_i = I.clone();
    //    J = ScanImageAndReduceIterator(clone_i, table);
    //}

    //t = 1000*((double)getTickCount() - t)/getTickFrequency();
    //t /= times;

    //cout << "Time of reducing with the iterator (averaged for "
    //    << times << " runs): " << t << " milliseconds."<< endl;

    //t = (double)getTickCount();

    //for (int i = 0; i < times; ++i)
    //{
    //    cv::Mat clone_i = I.clone();
    //    ScanImageAndReduceRandomAccess(clone_i, table);
    //}

    //t = 1000*((double)getTickCount() - t)/getTickFrequency();
    //t /= times;

    //cout << "Time of reducing with the on-the-fly address generation - at function (averaged for "
    //    << times << " runs): " << t << " milliseconds."<< endl;

    //Mat lookUpTable(1, 256, CV_8U);
    //uchar* p = lookUpTable.data;
    //for( int i = 0; i < 256; ++i)
    //    p[i] = table[i];

    //t = (double)getTickCount();

    //for (int i = 0; i < times; ++i)
    //    LUT(I, lookUpTable, J);

    //t = 1000*((double)getTickCount() - t)/getTickFrequency();
    //t /= times;

    //cout << "Time of reducing with the LUT function (averaged for "
    //    << times << " runs): " << t << " milliseconds."<< endl;
    //return 0;
}

Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() != sizeof(uchar));

    int channels = I.channels();

    int nRows = I.rows;
    int nCols = I.cols * channels;

    if (I.isContinuous())
    {
        nCols *= nRows;
        nRows = 1;
    }

    int i,j;
    uchar* p;
    for( i = 0; i < nRows; ++i)
    {
        p = I.ptr<uchar>(i);
        for ( j = 0; j < nCols; ++j)
        {
            p[j] = table[p[j]];
        }
    }
    return I;
}

Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() != sizeof(uchar));

    const int channels = I.channels();
    switch(channels)
    {
    case 1:
        {
            MatIterator_<uchar> it, end;
            for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)
                *it = table[*it];
            break;
        }
    case 3:
        {
            MatIterator_<Vec3b> it, end;
            for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it)
            {
                (*it)[0] = table[(*it)[0]];
                (*it)[1] = table[(*it)[1]];
                (*it)[2] = table[(*it)[2]];
            }
        }
    }

    return I;
}

Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table)
{
    // accept only char type matrices
    CV_Assert(I.depth() != sizeof(uchar));

    const int channels = I.channels();
    switch(channels)
    {
    case 1:
        {
            for( int i = 0; i < I.rows; ++i)
                for( int j = 0; j < I.cols; ++j )
                    I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];
            break;
        }
    case 3:
        {
         Mat_<Vec3b> _I = I;

         for( int i = 0; i < I.rows; ++i)
            for( int j = 0; j < I.cols; ++j )
               {
                   _I(i,j)[0] = table[_I(i,j)[0]];
                   _I(i,j)[1] = table[_I(i,j)[1]];
                   _I(i,j)[2] = table[_I(i,j)[2]];
            }
         I = _I;
         break;
        }
    }

    return I;
}